package com.yunpeng.aidevice.dao.service.impl;

import com.yunpeng.aidevice.common.constant.ConfigConstantValues;
import com.yunpeng.aidevice.dao.mapper.relation.*;
import com.yunpeng.aidevice.dao.service.ICodeGenerateCommonService;
import com.yunpeng.aidevice.dao.service.IFunctionNodeService;
import com.yunpeng.aidevice.common.enums.ResultCodeEnum;
import com.yunpeng.cache.util.DistributedLockHelper;
import com.yunpeng.common.exception.BizException;
import com.yunpeng.aidevice.dao.constant.DictionariesConstant;
import com.yunpeng.aidevice.dao.mapper.entity.FunctionNodeMapper;
import com.yunpeng.aidevice.dao.mapper.entity.PermissionMapper;
import com.yunpeng.aidevice.dao.mapper.entity.UserMapper;
import com.yunpeng.aidevice.dao.model.entity.FunctionNodeDO;
import com.yunpeng.aidevice.dao.model.entity.PermissionDO;
import com.yunpeng.aidevice.dao.model.entity.UserDO;
import com.yunpeng.aidevice.dao.model.relation.FunctionsNodeRelationPermissionsDO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * FunctionNodeServiceImpl 功能节点服务
 *
 * @author : Moore(hemw)
 * @date : 2020-04-10
 */
@Service
public class FunctionNodeServiceImpl implements IFunctionNodeService {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(FunctionNodeServiceImpl.class);

    /**
     * 当前服务的实体表名
     */
    private static final String TABLE_NAME = "t_ai_device_function_node";

    @Resource
    private ICodeGenerateCommonService codeGenerateCommonService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private FunctionNodeMapper functionNodeMapper;

    @Resource
    private UserOwnPermissionMapper userOwnPermissionMapper;

    @Resource
    private RolePermissionMapper rolePermissionMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private OrganizationPermissionMapper organizationPermissionMapper;

    @Resource
    private FunctionsNodeRelationPermissionsMapper functionsNodeRelationPermissionsMapper;

    @Resource
    private PermissionMapper permissionMapper;


    @Override
    /**
     * 根据节点代码获取节点对象
     *
     * @param nodeCode 节点代码
     * @return
     */
    public FunctionNodeDO getByCode(String nodeCode) {
        if (StringUtils.isBlank(nodeCode)) {
            return null;
        }
        return functionNodeMapper.getByCode(nodeCode);
    }

    @Override
    /**
     * 获取实时的用户可操作的功能集合
     *
     * @param userCode
     * @return
     */
    public List<FunctionNodeDO> getUserFunctionPermissionList(String userCode) {
        //无用户，返回空
        if (StringUtils.isBlank(userCode)) {
            return null;
        }
        //无用户，返回空
        UserDO userDO = userMapper.getByCode(userCode);
        if (userDO == null) {
            return null;
        }
        Date now = new Date();
        //用户自有权限
        List<String> userPermissions = userOwnPermissionMapper.queryPermissionCodeListByUser(userCode, now);
        if (userPermissions == null) {
            userPermissions = new ArrayList<>();
        }
        //处理用户角色
        List<String> userRoles = userRoleMapper.queryRoleCodeListByUser(userCode, now);
        if (userRoles == null) {
            userRoles = new ArrayList<>();
        }
        //系统运维人员处理
        if (userRoles.contains(DictionariesConstant.INSTANCE.getAdminRoleName())) {
            return queryAllList();
        }
        //补充用户登录后角色
        userRoles.add(DictionariesConstant.INSTANCE.getDefaultRoleName());
        //补充用户角色权限
        List<String> rolesPermissions = rolePermissionMapper.queryRoleListPermissions(userRoles);
        if (rolesPermissions != null) {
            userPermissions.addAll(rolesPermissions);
        }
        //补充组织权限
        if (userDO.getOrganizationCode() != null) {
            List<String> orgPermissions = organizationPermissionMapper.queryPermissionCodeListByOrg(userDO.getOrganizationCode(), now);
            if (orgPermissions != null) {
                userPermissions.addAll(orgPermissions);
            }
        }
        //无权限，返回空
        if (userPermissions.isEmpty()) {
            return null;
        }
        //过滤无效权限
        List<PermissionDO> finalPermissionList = permissionMapper.queryEffectivePermissionListByCode(userPermissions);
        //无有效权限，返回空
        if (finalPermissionList == null || finalPermissionList.isEmpty()) {
            return null;
        }
        //设定真正权限
        userPermissions = finalPermissionList.stream().map(t -> t.getCode()).collect(Collectors.toList());
        //查询对应的节点
        List<String> functionNodeCodeList = functionsNodeRelationPermissionsMapper.queryFunctionNodeListPermissions(userPermissions);
        return queryFunctionNodeByCodes(functionNodeCodeList);
    }


    @Override
    /**
     * 获取功能菜单文件夹
     *
     * @return
     */
    public List<FunctionNodeDO> getFolder() {
        Map<String, Object> param = new HashMap<>(16);
        param.put("flag", 1);
        param.put("folder", 1);
        param.put("tenant_code", DictionariesConstant.INSTANCE.getDefaultTenantCode());
        return functionNodeMapper.queryForList(param);
    }

    @Override
    /**
     * 新增功能节点
     *
     * @param name         功能名称
     * @param url          路径url
     * @param folder       是否文件夹
     * @param parentCode   父节点代码
     * @param operatorCode 操作人代码
     * @return
     */
    public Boolean addNew(String name, String url, Boolean folder, String parentCode, String operatorCode) {
        if (StringUtils.isBlank(name)) {
            return false;
        }
        if (StringUtils.isBlank(url)) {
            return false;
        }
        if (folder == null) {
            folder = false;
        }
        FunctionNodeDO saveDo = new FunctionNodeDO();
        saveDo.initForNew(operatorCode);
        if (StringUtils.isNotBlank(parentCode)) {
            FunctionNodeDO parent = functionNodeMapper.getByCode(parentCode);
            if (parent == null || parent.getId() == null) {
                throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "父节点不存在");
            }
            saveDo.setParentName(parent.getName());
            saveDo.setParentCode(parent.getCode());
        }
        saveDo.setUrl(url);
        saveDo.setFolder(folder);
        saveDo.setName(name);
        if (DistributedLockHelper.INSTANCE.getLock(TABLE_NAME, ConfigConstantValues.APPLICATION_NAME)) {
            saveDo.setCode(codeGenerateCommonService.generateCode(TABLE_NAME));
            try {
                functionNodeMapper.add(saveDo);
                return true;
            } catch (Exception ex) {
                LOGGER.error("save function node info error : {}", saveDo, ex);
                throw new BizException(ResultCodeEnum.SAVE_DATA_FAILED);
            } finally {
                codeGenerateCommonService.holdCountMinus(TABLE_NAME);
                DistributedLockHelper.INSTANCE.unlock(TABLE_NAME, ConfigConstantValues.APPLICATION_NAME);
            }
        } else {
            return false;
        }
    }

    @Override
    /**
     * 删除功能节点
     *
     * @param functionNodeCode 功能节点代码
     * @return
     */
    public Boolean remove(String functionNodeCode) {
        if (StringUtils.isBlank(functionNodeCode)) {
            return false;
        }
        FunctionNodeDO functionNodeDO = functionNodeMapper.getByCode(functionNodeCode);
        if (functionNodeDO == null || functionNodeDO.getId() == null) {
            return true;
        }
        functionNodeMapper.delete(functionNodeDO.getId());
        functionsNodeRelationPermissionsMapper.deleteByFunctionNode(functionNodeCode);
        return true;
    }


    @Override
    /**
     * 获取所有功能节点列表数据
     * 限制在1000条以内
     *
     * @return
     */
    public List<FunctionNodeDO> queryAllList() {
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("flag", 1);
        queryMap.put("tenant_code", DictionariesConstant.INSTANCE.getDefaultTenantCode());
        return functionNodeMapper.queryForList(queryMap);
    }

    @Override
    /**
     * 功能节点绑定权限
     *
     * @param nodeCode        功能节点代码
     * @param permissionCodes 权限代码集合
     * @param operatorCode    操作人代码
     * @return
     */
    public Boolean bindPermission(String nodeCode, List<String> permissionCodes, String operatorCode) {
        if (StringUtils.isBlank(nodeCode)) {
            return false;
        }
        if (permissionCodes == null || permissionCodes.isEmpty()) {
            return false;
        }
        FunctionNodeDO functionNodeDO = functionNodeMapper.getByCode(nodeCode);
        if (functionNodeDO == null || functionNodeDO.getId() == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "功能节点不存在！");
        }
        List<PermissionDO> permissionDOList = permissionMapper.queryPermissionListByCode(permissionCodes);
        if (permissionDOList == null || permissionDOList.isEmpty()) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "权限不存在！");
        }
        try {
            doBatchAdd(nodeCode, permissionCodes, functionNodeDO, permissionDOList, operatorCode);
            return true;
        } catch (Exception ex) {
            LOGGER.error("transaction batch add data error,nodeCode {},permission list {}.", nodeCode, permissionCodes, ex);
            return false;
        }
    }

    @Override
    /**
     * 根据功能节点代码查询关联集合
     *
     * @param nodeCode 功能节点代码
     * @return
     */
    public List<FunctionsNodeRelationPermissionsDO> queryRelationListByNodeCode(String nodeCode) {
        if (StringUtils.isBlank(nodeCode)) {
            return null;
        }
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("flag", 1);
        queryMap.put("function_node_code", nodeCode);
        return functionsNodeRelationPermissionsMapper.queryForList(queryMap);
    }

    //region 私有方法

    /**
     * 根据功能节点代码查询功能节点
     *
     * @param nodeCodes
     * @return
     */
    private List<FunctionNodeDO> queryFunctionNodeByCodes(List<String> nodeCodes) {
        List<FunctionNodeDO> result = functionNodeMapper.queryPureNodeListByCodes(nodeCodes);
        //结果集为空
        if (result == null || result.isEmpty()) {
            return null;
        }
        //加上文件夹节点
        List<FunctionNodeDO> folderList = getFolder();
        if (folderList != null) {
            result.addAll(folderList);
        }
        return result;
    }

    /**
     * 获取所有功能节点
     *
     * @return
     */
    private List<FunctionNodeDO> queryAllFunctionNode() {
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("flag", 1);
        queryMap.put("tenant_code", DictionariesConstant.INSTANCE.getDefaultTenantCode());
        return functionNodeMapper.queryForList(queryMap);
    }

    /**
     * 批量添加（事务）
     *
     * @param nodeCode
     * @param permissionCodes
     * @param functionNodeDO
     * @param permissionDOList
     * @param operatorCode
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 3600, rollbackFor = Exception.class)
    void doBatchAdd(String nodeCode, List<String> permissionCodes, FunctionNodeDO functionNodeDO, List<PermissionDO> permissionDOList, String operatorCode) {
        //清理原有绑定
        functionsNodeRelationPermissionsMapper.clearRelation(nodeCode, permissionCodes);
        List<FunctionsNodeRelationPermissionsDO> batchAddDoList = new ArrayList<>();
        for (PermissionDO permissionDO : permissionDOList) {
            FunctionsNodeRelationPermissionsDO functionsNodeRelationPermissionsDO = new FunctionsNodeRelationPermissionsDO();
            functionsNodeRelationPermissionsDO.initForNew(operatorCode);
            functionsNodeRelationPermissionsDO.setFunctionNodeCode(functionNodeDO.getCode());
            functionsNodeRelationPermissionsDO.setFunctionNodeName(functionNodeDO.getName());
            functionsNodeRelationPermissionsDO.setPermissionCode(permissionDO.getCode());
            functionsNodeRelationPermissionsDO.setPermissionName(permissionDO.getName());
            batchAddDoList.add(functionsNodeRelationPermissionsDO);
        }
        //执行新增
        functionsNodeRelationPermissionsMapper.batchAdd(batchAddDoList);
    }
    //endregion
}
